#include "tim_encode.h"
#include "tim_irq.h"
#include "../lib/inc/stm32f10x_conf.h"
#include "io.h"

#define SET_DIR(tim) encode_dir |= (1 << tim)
#define CLN_DIR(tim) encode_dir &= ~(1 << tim)
#define GET_DIR(tim) (!!(encode_dir&(1 << tim)))

#define TO_TIM(t) (t <= ENCODE_TIM5 ? t : \
            (t <= ENCODE_TIM3_PARTIAL ? (t - ENCODE_TIM1_PARTIAL) : t - ENCODE_TIM1_FULL))

const uint8_t encode_pins[][2] = {
    {PA8, PA9},  // TIM1
    {PA0, PA1},  // TIM2
    {PA6, PA7},  // TIM3
    {PB6, PB7},  // TIM4
    {PA0, PA1},  // TIM5
    // PARTIAL REMAP
    {PA7, PB0},  // TIM1
    {PA15, PB3},  // TIM2
    {PB4, PB5},  // TIM3
    // FULL REMAP
    {PE9, PE11},  // TIM1
    {PA15, PB3},  // TIM2
    {PC6, PC7},  // TIM3
    {PD12, PD13},  // TIM4

};
const uint32_t encode_remap[] = {
    GPIO_PartialRemap_TIM1,
    GPIO_PartialRemap1_TIM2,
    GPIO_PartialRemap_TIM3,
    GPIO_FullRemap_TIM1,
    GPIO_FullRemap_TIM2,
    GPIO_FullRemap_TIM3,
    GPIO_Remap_TIM4,
};

static TIM_TypeDef * tim_table[] = {TIM1, TIM2, TIM3, TIM4, TIM5};
static const uint32_t rcc_tim[] = {RCC_APB2Periph_TIM1, RCC_APB1Periph_TIM2, RCC_APB1Periph_TIM3, RCC_APB1Periph_TIM4, RCC_APB1Periph_TIM5};
static const uint32_t irqn_tim[] = {TIM1_UP_IRQn, TIM2_IRQn, TIM3_IRQn, TIM4_IRQn, TIM5_IRQn};
TIM_FUN encode_ieq_fun[] = {TIM1_EncodeIrq, TIM2_EncodeIrq, TIM3_EncodeIrq, TIM4_EncodeIrq, TIM5_EncodeIrq};
static uint8_t encode_dir = 0;
static int32_t encode_count[5] = {0};

void TimEncodeInit(ENCODE_TIM_E tim_chn) {
	NVIC_InitTypeDef   NVIC_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_ICInitTypeDef TIM_ICInitStructure;
    uint8_t tim = TO_TIM(tim_chn);
    if (tim == ENCODE_TIM1) {
	    RCC_APB2PeriphClockCmd(rcc_tim[tim], ENABLE);
    } else {
        RCC_APB1PeriphClockCmd(rcc_tim[tim], ENABLE);
    }
	IOInit(encode_pins[tim_chn][0], Mode_IN_FLOATING);
    IOInit(encode_pins[tim_chn][1], Mode_IN_FLOATING);
    if (tim_chn >= ENCODE_TIM1_PARTIAL) {
        GPIO_PinRemapConfig(encode_remap[tim_chn - ENCODE_TIM1_PARTIAL],ENABLE);
    }

	/* 配置中断使用组合  抢占式3位(0-7)，响应式1位(0-1) */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
	NVIC_InitStructure.NVIC_IRQChannel = irqn_tim[tim]; 
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
	NVIC_Init(&NVIC_InitStructure);

	TIM_DeInit(tim_table[tim]);
	TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
	TIM_TimeBaseStructure.TIM_Period = OVERFLOW_COUNT;
	TIM_TimeBaseStructure.TIM_Prescaler = 0;
	TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(tim_table[tim], &TIM_TimeBaseStructure);

	TIM_EncoderInterfaceConfig(tim_table[tim], TIM_EncoderMode_TI12, TIM_ICPolarity_BothEdge ,TIM_ICPolarity_BothEdge);
	TIM_ICStructInit(&TIM_ICInitStructure);
	TIM_ICInitStructure.TIM_ICFilter = 6;
	TIM_ICInit(tim_table[tim], &TIM_ICInitStructure);

	TIM_ClearFlag(tim_table[tim], TIM_FLAG_Update);
	TIM_ITConfig(tim_table[tim], TIM_IT_Update, ENABLE);
	//Reset counter
	tim_table[tim]->CNT = 0;//

	TIM_Cmd(tim_table[tim], ENABLE);	 //启动定时器
    SetTimIrqFun((IRQ_TIM_E)tim, encode_ieq_fun[tim]);
}

int TimEncodeGet(ENCODE_TIM_E tim) {
    tim = (ENCODE_TIM_E)TO_TIM(tim);
    int ret = encode_count[tim];
    ret += (-GET_DIR(tim) * OVERFLOW_COUNT + tim_table[tim]->CNT);
    tim_table[tim]->CNT = 0;
    CLN_DIR(tim);
    encode_count[tim] = 0;
    return ret;
}

void TIM1_EncodeIrq(void) {
    // if((TIM1->CR1 & TIM_CounterMode_Down) == TIM_CounterMode_Down) {
    //     SET_DIR(ENCODE_TIM1);
    //     encode_count[ENCODE_TIM1] += (tim_table[ENCODE_TIM2]->CNT - OVERFLOW_COUNT);
    // } else {
    //     CLN_DIR(ENCODE_TIM2);
    //     encode_count[ENCODE_TIM2] += tim_table[ENCODE_TIM2]->CNT;
    // }
}

void TIM2_EncodeIrq(void) {
    if((TIM2->CR1 & TIM_CounterMode_Down) == TIM_CounterMode_Down) {
        SET_DIR(ENCODE_TIM2);
        encode_count[ENCODE_TIM2] += (tim_table[ENCODE_TIM2]->CNT - OVERFLOW_COUNT);
    } else {
        CLN_DIR(ENCODE_TIM2);
        encode_count[ENCODE_TIM2] += tim_table[ENCODE_TIM2]->CNT;
    }
}

void TIM3_EncodeIrq(void) {
    if((TIM3->CR1 & TIM_CounterMode_Down) == TIM_CounterMode_Down) {
        SET_DIR(ENCODE_TIM3);
        encode_count[ENCODE_TIM3] += (tim_table[ENCODE_TIM3]->CNT - OVERFLOW_COUNT);
    } else {
        CLN_DIR(ENCODE_TIM3);
        encode_count[ENCODE_TIM3] += tim_table[ENCODE_TIM3]->CNT;
    }
}

void TIM4_EncodeIrq(void) {
    if((TIM4->CR1 & TIM_CounterMode_Down) == TIM_CounterMode_Down) {
        SET_DIR(ENCODE_TIM4);
        encode_count[ENCODE_TIM4] += (tim_table[ENCODE_TIM4]->CNT - OVERFLOW_COUNT);
    } else {
        CLN_DIR(ENCODE_TIM4);
        encode_count[ENCODE_TIM4] += tim_table[ENCODE_TIM4]->CNT;
    }
}

void TIM5_EncodeIrq(void) {
    if((TIM5->CR1 & TIM_CounterMode_Down) == TIM_CounterMode_Down) {
        SET_DIR(ENCODE_TIM5);
        encode_count[ENCODE_TIM5] += (tim_table[ENCODE_TIM5]->CNT - OVERFLOW_COUNT);
    } else {
        CLN_DIR(ENCODE_TIM5);
        encode_count[ENCODE_TIM5] += tim_table[ENCODE_TIM5]->CNT;
    }
}
